#include <stdint.h>
#include <string.h>

#include "interface.h"
#include "pcd.h"
#include "pcd_def.h"
#include "rc522.h"
#include <stdio.h>

bool rc522_tag_eq(struct rc522_tag *tag1, struct rc522_tag *tag2)
{
	if (tag1->tag_type[0] != tag2->tag_type[0])
		return false;
	if (tag1->tag_type[1] != tag2->tag_type[1])
		return false;
	for (int i = 0; i < 4; i++) {
		if (tag1->tag_serial_num[i] != tag2->tag_serial_num[i])
			return false;
	}
	return true;
}

void rc522_init(void)
{
	// 必须先初始化接口
	rc522_interface_init();

	// 复位
	pcd_reset();
	delay_ms(5);

	/**
         * 保存pcd状态的寄存器,据此返回值，可以用于判断是否初始化成功
         * 
         * Status1Reg
         * 包含 CRC、中断和 FIFO 缓冲区的状态标志。
         * 
         * Status2Reg
         * 包含接收器、发送器和数据模式检测器的状态标志。
         * 
         * WaterLevelReg
         * 定义 FIFO 下溢和上溢报警的 FIFO 深度。
         */
	// printf("reg: %02x", read_reg(Status1Reg));
	// printf("reg: %02x", read_reg(Status2Reg));
	// printf("reg: %02x", read_reg(WaterLevelReg));

	// 开启天线发射
	pcd_antenna_on();
}

void rc522_free(void)
{
	pcd_antenna_off();
	rc522_interface_free();
}

rc522_err_t rc522_scan(struct rc522_tag *tag)
{
	memset(tag, 0, sizeof(struct rc522_tag));

	if (pcd_request(PICC_REQALL, tag->tag_type) != PCD_OK)
		return RC522_NOTAG;

	if (pcd_anticoll(tag->tag_serial_num) != PCD_OK)
		return RC522_ANTICOLL_FAIL;

	return RC522_OK;
}

static inline rc522_err_t rc522_read_m1_s50(const struct rc522_tag *tag,
					    const uint8_t key_A[6],
					    uint8_t addr, uint8_t data[16])
{
	if (pcd_select(tag->tag_serial_num) != PCD_OK)
		return RC522_SELECT_FAIL;

	if (pcd_auth(0x60, addr, key_A, tag->tag_serial_num) != PCD_OK)
		return RC522_AUTH_FAIL;

	if (pcd_read(addr, data) != PCD_OK)
		return RC522_READ_FAIL;

	return RC522_OK;
}
static inline rc522_err_t rc522_write_m1_s50(const struct rc522_tag *tag,
					     const uint8_t key_A[6],
					     uint8_t addr, const uint8_t data[16])
{
	if (pcd_select(tag->tag_serial_num) != PCD_OK)
		return RC522_SELECT_FAIL;

	if (pcd_auth(0x60, addr, key_A, tag->tag_serial_num) != PCD_OK)
		return RC522_AUTH_FAIL;

	if (pcd_write(addr, data) != PCD_OK)
		return RC522_WRITE_FAIL;

	return RC522_OK;
}

enum {
	M0 = 0x4400,
	M1_S50 = 0x0400,
	M1_S70 = 0x0200,
	M2 = 0x0800,
	M3 = 0x4403,
};

static inline uint16_t tag_type_to_u16(const uint8_t tag_type[2])
{
	return (tag_type[0] << 8) + tag_type[1];
}

rc522_err_t rc522_read(const struct rc522_tag *tag, const uint8_t key_A[6],
		       uint8_t addr, uint8_t data[16])
{
	uint16_t tag_type = tag_type_to_u16(tag->tag_type);
	if (tag_type == M1_S50) {
		if (addr >= 16 * 4)
			return RC522_ADDR_OUT_OF_RANGE;
		return rc522_read_m1_s50(tag, key_A, addr, data);
	}

	else
		return RC522_UNSUPPORT_TAGTYPE;
}

rc522_err_t rc522_write(const struct rc522_tag *tag, const uint8_t key_A[6],
			uint8_t addr, const uint8_t data[16])
{
	uint16_t tag_type = tag_type_to_u16(tag->tag_type);
	if (tag_type == M1_S50) {
		if (addr >= 16 * 4)
			return RC522_ADDR_OUT_OF_RANGE;
		return rc522_write_m1_s50(tag, key_A, addr, data);
	}

	else
		return RC522_UNSUPPORT_TAGTYPE;
}

rc522_err_t rc522_read_any(struct rc522_tag *tag, const uint8_t key_A[6],
			   uint8_t addr, uint8_t data[16])
{
	rc522_err_t err;
	err = rc522_scan(tag);
	if (err != RC522_OK)
		return err;

	err = rc522_read(tag, key_A, addr, data);
	if (err != RC522_OK)
		return err;

	return RC522_OK;
}

rc522_err_t rc522_write_any(struct rc522_tag *tag, const uint8_t key_A[6],
			    uint8_t addr, const uint8_t data[16])
{
	rc522_err_t err;
	err = rc522_scan(tag);
	if (err != RC522_OK)
		return err;

	err = rc522_write(tag, key_A, addr, data);
	if (err != RC522_OK)
		return err;

	return RC522_OK;
}